# coding=utf-8

from typing import Dict, List
from generator.libsomeip.some_ip_type import Message, SomeIP
from generator.libsomeip.Common import isArray, isNormal, isString, isStruct, parseType
from string import Template
from utils.payload import TypeEnum

from utils.util import writeFile

templete_h=Template(
"""#pragma once

#include <transfer/common.h>
#include <vsomeip/vsomeip.hpp>
#include <vector>
#include <cstdint>

namespace ecarx::transfer::someip{
    
    std::shared_ptr<vsomeip::message> convertSignal2SomeipMessage(const Signal&);

}
"""
)

templete_cpp=Template(
"""#include "ConvertSignal2SomeIP.h"
#include "someip/someip_signals.h"
#include "someip/someip_structs.h"
#include <string.h>

namespace ecarx::transfer::someip{
${buffers}
    std::shared_ptr<vsomeip::message> convertSignal2SomeipMessage(const Signal& signal){
        std::shared_ptr<vsomeip::message> request=vsomeip::runtime::get()->create_request(true);
        request->set_service(${service_id});
        request->set_instance(${instance_id});
        std::shared_ptr<vsomeip::payload> payload = vsomeip::runtime::get()->create_payload();
        switch(signal.signalId){
${templete_cases}
        }
        request->set_payload(payload);
        return request;
    }
}
"""
)

templete_buffer=Template(
"""
    static uint8_t ${buffer_name}[${len}]={${init}};
"""
)

templete_base_type_signal_case=Template(
"""
            case static_cast<int32_t>(${signal_id}):{
                
                request->set_method(${method_id});
                request->set_message_type(vsomeip::message_type_e::MT_${message_type});
                request->set_reliable(${ip_type});
                constexpr uint32_t len=sizeof(${signal_type});
                uint8_t buffer[len]{};
                ${signal_type} value=${convert_type}signal.value.${prop}[0];
                memcpy(buffer,&value,len);
                payload->set_data(buffer,len);
                break;
            }"""
)

templete_string_signal_case=Template(
"""
            case static_cast<int32_t>(${signal_id}):{
                request->set_method(${method_id});
                request->set_message_type(vsomeip::message_type_e::MT_${message_type});
                request->set_reliable(${ip_type});
                payload->set_data(signal.value.stringValue.c_str(),signal.value.stringValue.size());
                break;
            }"""
)

templete_struct_signal_case=Template(
"""
            case static_cast<int32_t>(${signal_id}):{
                request->set_method(${method_id});
                request->set_message_type(vsomeip::message_type_e::MT_${message_type});
                request->set_reliable(${ip_type});
                payload->set_data(signal.value.bytes);
                break;
            }"""
)

templete_int8_array_signal_case=Template(
"""
            case static_cast<int32_t>(${signal_id}):{
                request->set_method(${method_id});
                request->set_message_type(vsomeip::message_type_e::MT_${message_type});
                payload->set_data(signal.value.bytes);
                break;
            }"""
)

#暂时不支持一下数组类型传递
# templete_int16_array_signal_case=Template(
# """
#             case static_cast<int32_t>(${signal_id}):{
#                 request->set_service(${service_id});
#                 request->set_method(${method_id});
#                 request->set_message_type(vsomeip::message_type_e::MT_${message_type});
#                 uint8_t buffer[${payload_len}]{};
#                 for(size_t i=0;i<${payload_len};i+=2){
#                     ${signal_type} value=${signal_type}signal.value.int32Values[i];
#                     memcpy(buffer+i,&value,2);
#                 }
#                 payload->set_data(buffer,${payload_len});
#                 break;
#             }"""
# )
# templete_int32_array_signal_case=Template(
# """
#             case static_cast<int32_t>(${signal_id}):{
#                 request->set_service(${service_id});
#                 request->set_method(${method_id});
#                 request->set_message_type(vsomeip::message_type_e::MT_${message_type});
#                 uint8_t buffer[${payload_len}]{};
#                 for(size_t i=0;i<${payload_len};i+=4){
#                     int32_t value=signal.value.int32Values[i];
#                     memcpy(buffer+i,&value,4);
#                 }
#                 payload->set_data(buffer,${payload_len});
#                 break;
#             }"""
# )

# templete_int64_array_signal_case=Template(
# """
#             case static_cast<int32_t>(${signal_id}):{
#                 request->set_service(${service_id});
#                 request->set_method(${method_id});
#                 request->set_message_type(vsomeip::message_type_e::MT_${message_type});
#                 uint8_t buffer[${payload_len}]{};
#                 for(size_t i=0;i<${payload_len};i+=8){
#                     int64_t value=signal.value.int64Values[i];
#                     memcpy(buffer+i,&value,8);
#                 }
#                 payload->set_data(buffer,${payload_len});
#                 break;
#             }"""
# )

# templete_float_array_signal_case=Template(
# """
#             case static_cast<int32_t>(${signal_id}):{
#                 request->set_service(${service_id});
#                 request->set_method(${method_id});
#                 request->set_message_type(vsomeip::message_type_e::MT_${message_type});
#                 uint8_t buffer[${payload_len}]{};
#                 for(size_t i=0;i<${payload_len};i+=4){
#                     float value=signal.value.floatValues[i];
#                     memcpy(buffer+i,&value,4);
#                 }
#                 payload->set_data(buffer,${payload_len});
#                 break;
#             }"""
# )

#目前协议里只有拆分了一组uint8的信号,因此这里只实现这一个
templete_buffer_uint8_case=Template(
"""
            case static_cast<int32_t>(${signal_id}):{
                request->set_service(${service_id});
                request->set_method(${method_id});
                request->set_message_type(vsomeip::message_type_e::MT_${message_type});
                uint8_t value = (uint8_t)signal.value.int32Values[0];
                memcpy(${buffer_ptr}+${offset},&value,${copy_len});
                payload->set_data(${buffer_ptr},sizeof(${buffer_ptr}));
                break;
            }"""
)

templete_buffer_other_case=Template(
"""
            case static_cast<int32_t>(${signal_id}):{
                request->set_service(${service_id});
                request->set_method(${method_id});
                request->set_message_type(vsomeip::message_type_e::MT_${message_type});
                //todo 暂不支持处理该类型
                payload->set_data(${buffer_ptr},sizeof(${buffer_ptr}));
                break;
            }"""
)

templete_buffer_uint8_array_case=Template(
"""
            case static_cast<int32_t>(${signal_id}):{
                request->set_service(${service_id});
                request->set_method(${method_id});
                request->set_message_type(vsomeip::message_type_e::MT_${message_type});
                for(size_t i =0;i<${copy_len};++i){
                    ${buffer_ptr}[${offset}+i]=signal.value.bytes[i];
                }
                payload->set_data(${buffer_ptr},sizeof(${buffer_ptr}));
                break;
            }"""
)


def gen_convert2someIp(someip:SomeIP):
    signal_id_cases=[]
    buffers=[]

    for msg in someip.msg:
        # msg.getterId == '0x0' and  getter not support
        if msg.setterId == '0x0' and msg.methodId == '0x0':
            #no send event
            continue

        idtItemList = someip.idtItemDict.get(msg.idtName, None)
        if idtItemList is None:
            print("!!!!!! lost idtname in gen_convert2someIp:", msg.idtName)
            continue

        signalStr = ""
        methodStr = ""
        if msg.setterId != '0x0':
            methodStr = "{}Setter".format(msg.msgName)
            signalStr = "SOMEIPTX::{}SetterId".format(msg.msgName)
        if msg.methodId != '0x0':
            methodStr = "{}Method".format(msg.msgName)
            signalStr = "SOMEIPTX::{}MethodId".format(msg.msgName)

        idtItem = idtItemList[0]
        buffer_parses=[]
        if isNormal(idtItem.idtType) == True:
            dest_type, dest_len, convert_type, c_type = parseType(idtItem.idtType)
            signal_id_cases.append(templete_base_type_signal_case.substitute(
                signal_id=signalStr,
                method_id=methodStr,
                message_type="REQUEST_NO_RETURN", #no return now
                ip_type="true" if msg.isTcp else "false",
                signal_type="{}_t".format(idtItem.idtType),
                convert_type=convert_type,
                prop=dest_type
            ))
        elif isStruct(idtItem.idtType) == True or isArray(idtItem.idtType) == True:
            signal_id_cases.append(templete_struct_signal_case.substitute(
                signal_id=signalStr,
                method_id=methodStr,
                message_type="REQUEST_NO_RETURN", #no return now,
                ip_type="true" if msg.isTcp else "false"
            ))
        elif isString(idtItem.idtType) == True:
            signal_id_cases.append(templete_string_signal_case.substitute(
                signal_id=signalStr,
                method_id=methodStr,
                message_type="REQUEST_NO_RETURN",
                ip_type="true" if msg.isTcp else "false"
            ))


    writeFile("./data/transfer/libsomeip/src", "ConvertSignal2SomeIP.h",
              lambda file: file.write(templete_h.substitute()))
    writeFile("./data/transfer/libsomeip/src", "ConvertSignal2SomeIP.cpp", lambda file:
              file.write(templete_cpp.substitute(
                  service_id="ADCU_HMI_SERVICE_ID",
                  instance_id="ADCU_HMI_INSTANCE_ID",
                  templete_cases="".join(signal_id_cases),
                  buffers="".join(buffers)
              )))

    